// import com.alibaba.druid.sql.ast.SQLDeclareItem;
// import com.alibaba.druid.sql.ast.SQLObject;
// import com.alibaba.druid.sql.ast.SQLOver;
// import com.alibaba.druid.sql.ast.SQLParameter;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.HashMap;
// import java.util.std::map;

// import static com.alibaba.druid.sql.repository.SchemaResolveVisitorFactory.*;

#include "SchemaResolveVisitor.h"
#include "../ast/SQLDeclareItem.h"
#include "../ast/SQLName.h"
#include "../ast/expr/SQLCastExpr.h"
#include "SchemaResolveVisitorFactory.h"

SchemaResolveVisitor_Option_ptr SchemaResolveVisitor_Option::ResolveAllColumn = SchemaResolveVisitor_Option_ptr(new SchemaResolveVisitor_Option(1 << 0, make_string_ptr("ResolveAllColumn")));
SchemaResolveVisitor_Option_ptr SchemaResolveVisitor_Option::ResolveIdentifierAlias = SchemaResolveVisitor_Option_ptr(new SchemaResolveVisitor_Option(1 << 1, make_string_ptr("ResolveIdentifierAlias")));
SchemaResolveVisitor_Option_ptr SchemaResolveVisitor_Option::CheckColumnAmbiguous = SchemaResolveVisitor_Option_ptr(new SchemaResolveVisitor_Option(1 << 2, make_string_ptr("CheckColumnAmbiguous")));

SchemaResolveVisitor_Option::SchemaResolveVisitor_Option(uint64_t mask, string_ptr name)
{
  this->mask_ = mask;
  this->name_ = name->c_str();
}

int SchemaResolveVisitor_Option::of(SchemaResolveVisitor_Option_list_ptr options)
{
  if (options == nullptr)
  {
    return 0;
  }

  int value = 0;

  for (SchemaResolveVisitor_Option_ptr option : *options)
  {
    value |= option->mask_;
  }

  return value;
}

SchemaResolveVisitor_Context::SchemaResolveVisitor_Context(SQLObject_ptr object, SchemaResolveVisitor_Context_ptr parent)
{
  this->object = object;
  this->parent = parent;
  this->level = parent == nullptr
                    ? 0
                    : parent->level + 1;
}

SQLTableSource_ptr SchemaResolveVisitor_Context::getFrom()
{
  return from;
}

void SchemaResolveVisitor_Context::setFrom(SQLTableSource_ptr from)
{
  this->from = from;
}

SQLTableSource_ptr SchemaResolveVisitor_Context::getTableSource()
{
  return tableSource;
}

void SchemaResolveVisitor_Context::setTableSource(SQLTableSource_ptr tableSource)
{
  this->tableSource = tableSource;
}

void SchemaResolveVisitor_Context::addTableSource(long alias_hash, SQLTableSource_ptr tableSource)
{
  // if (tableSourceMap == nullptr)
  // {
  //   tableSourceMap = new HashMap<long, SQLTableSource_ptr>();
  // }

  tableSourceMap.insert(std::make_pair(alias_hash, tableSource));
}

void SchemaResolveVisitor_Context::declare(SQLDeclareItem_ptr x)
{
  // if (declares == nullptr)
  // {
  //   declares = new HashMap<long, SQLDeclareItem_ptr>();
  // }
  declares.insert(std::make_pair(x->getName()->nameHashCode64(), x));
}

SQLDeclareItem_ptr SchemaResolveVisitor_Context::findDeclare(long nameHash)
{
  if (declares.empty())
  {
    return nullptr;
  }
  auto tmp = declares.find(nameHash);
  if (tmp != declares.end())
  {
    return tmp->second;
  }

  return nullptr;
}

SQLTableSource_ptr SchemaResolveVisitor_Context::findTableSource(long nameHash)
{
  SQLTableSource_ptr table = nullptr;
  if (!tableSourceMap.empty())
  {
    auto tmp = tableSourceMap.find(nameHash);
    if (tmp != tableSourceMap.end())
    {
      table = tmp->second;
    }
  }

  return table;
}

SQLTableSource_ptr SchemaResolveVisitor_Context::findTableSourceRecursive(long nameHash)
{
  for (SchemaResolveVisitor_Context *ctx = this; ctx != nullptr; ctx = ctx->parent.get())
  {
    if (!ctx->tableSourceMap.empty())
    {
      auto tmp = ctx->tableSourceMap.find(nameHash);
      SQLTableSource_ptr table = nullptr;
      if (tmp != ctx->tableSourceMap.end())
      {
        table = tmp->second;
      }
      if (table != nullptr)
      {
        return table;
      }
    }
  }

  return nullptr;
}

BOOL_ptr SchemaResolveVisitor::isEnabled(SchemaResolveVisitor_Option_ptr option) {}

int SchemaResolveVisitor::getOptions() {}

SchemaRepository_ptr SchemaResolveVisitor::getRepository() {}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitor::getContext() {}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitor::createContext(SQLObject_ptr object) {}

void SchemaResolveVisitor::popContext() {}

bool SchemaResolveVisitor::visit(SQLSelectStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x->getSelect());
  return false;
}

bool SchemaResolveVisitor::visit(SQLSelect_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLWithSubqueryClause_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

// BOOL_ptr SchemaResolveVisitor::visit(SQLIfStatement_ptr x)
// {
//   // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitor::visit(SQLCreateFunctionStatement_ptr x)
// {
//   // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

bool SchemaResolveVisitor::visit(SQLExprTableSource_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLSelectQueryBlock_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLForeignKeyImpl_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLIdentifierExpr_ptr x)
{
  // SchemaResolveVisitorFactory::resolveIdent(this, x);
  return true;
}

bool SchemaResolveVisitor::visit(SQLPropertyExpr_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLBinaryOpExpr_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLAllColumnExpr_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLCreateTableStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLUpdateStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLDeleteStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

// BOOL_ptr SchemaResolveVisitor::visit(SQLAlterTableStatement_ptr x)
// {
//   // resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

bool SchemaResolveVisitor::visit(SQLInsertStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLParameter_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLDeclareItem_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLOver_ptr x)
{
  // resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLMethodInvokeExpr_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

bool SchemaResolveVisitor::visit(SQLUnionQuery_ptr x)
{
  // SchemaResolveVisitorFactory::resolveUnion(SharedObject(SchemaResolveVisitor), x);
  return false;
}

// BOOL_ptr SchemaResolveVisitor::visit(SQLMergeStatement_ptr x)
// {
//   // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitor::visit(SQLCreateProcedureStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

bool SchemaResolveVisitor::visit(SQLBlockStatement_ptr x)
{
  // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
  return false;
}

// BOOL_ptr SchemaResolveVisitor::visit(SQLReplaceStatement_ptr x)
// {
//   // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }

bool SchemaResolveVisitor::visit(SQLCastExpr_ptr x)
{
  x->getExpr()->accept(std::make_shared<SchemaResolveVisitor>(*this));
  return true;
}

// BOOL_ptr SchemaResolveVisitor::visit(SQLFetchStatement_ptr x)
// {
//   // SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitor), x);
//   return BOOL::FALSE;
// }
